package com.hc.programming.number;

import java.util.ArrayList;
import java.util.List;

/**
 * 43.给定两个以字符串形式表示的非负整数 num1 和 num2，返回 num1 和 num2 的乘积，它们的乘积也表示为字符串形式。
 * 注意：不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
 * <p>
 * 示例 1:
 * 输入: num1 = "2", num2 = "3"
 * 输出: "6"
 * <p>
 * 示例 2:
 * 输入: num1 = "123", num2 = "456"
 * 输出: "56088"
 * <p>
 * 提示：
 * 1 <= num1.length, num2.length <= 200
 * num1 和 num2 只能由数字组成。
 * num1 和 num2 都不包含任何前导零，除了数字0本身
 *
 * @author huangchao E-mail:fengquan8866@163.com
 * @version 创建时间：2024/6/15 22:28
 */
public class 字符串相乘 {
    public static void main(String[] args) {
        System.out.println(multiply("123456789", "987654321"));
        System.out.println(multiply3("123456789", "987654321"));
        System.out.println(multiply("123", "456"));
        System.out.println(multiply4("123", "456"));
    }

    /**
     * 方案一：同乘法笔算步骤:11ms
     */
    public static String multiply(String num1, String num2) {
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        List<StringBuilder> sbs = new ArrayList<>();
        for (int i = num2.length() - 1; i >= 0; i--) {
            StringBuilder sb = new StringBuilder(); // 存储反转的数字
            sbs.add(sb);
            for (int k = num2.length() - 1; k > i; k--) { // 补0
                sb.append('0');
            }
            int n1 = num2.charAt(i) - '0';
            int jinwei = 0; // 进位
            for (int j = num1.length() - 1; j >= 0; j--) {
                int n2 = num1.charAt(j) - '0';
                int stepM = n1 * n2 + jinwei; // 单步积
                jinwei = stepM / 10;
                sb.append(stepM % 10);
            }
            if (jinwei > 0) {
                sb.append(jinwei);
            }
        }
        // 累加
        int weishu = sbs.get(sbs.size() - 1).length(); // 位数 <= 数字位数之和
        StringBuilder res = new StringBuilder();
        int jinwei = 0; // 进位
        for (int i = 0; i < weishu; i++) {
            int stepSum = jinwei; // 单步求和
            for (StringBuilder sb : sbs) {
                if (sb.length() <= i) continue;
                stepSum += sb.charAt(i) - '0';
            }
            jinwei = stepSum / 10;
            res.append(stepSum % 10);
        }
        if (jinwei > 0) res.append(jinwei);
        return res.reverse().toString();
    }

    /**
     * 方案二：根据相乘后位数来计算:3ms
     */
    public static String multiply2(String num1, String num2) {
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        StringBuilder res = new StringBuilder();
        int m = num1.length();
        int n = num2.length();
        int jinwei = 0;
        int sum = 0;
        for (int i = 0; i < m + n; i++) {
            sum = jinwei;
            for (int j = 0; j <= i; j++) {
                if (j < m && (i - j) < n) {
                    sum += (num1.charAt(m - 1 - j) - '0') * (num2.charAt(n - 1 - (i - j)) - '0');
                }
            }
            if (sum == 0 && (i == m + n - 1)) continue;
            if (sum > 9) {
                res.append(sum % 10);
                jinwei = sum / 10;
            } else {
                res.append(sum);
                jinwei = 0;
            }
        }
        return res.reverse().toString();
    }

    /**
     * 方案三：同方案2，改用数组:3ms
     */
    public static String multiply3(String num1, String num2) {
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        int m = num1.length();
        int n = num2.length();
        int[] arr = new int[m + n];
        int jinwei = 0;
        int sum = 0;
        int i = 0;
        for (i = 0; i < m + n - 1; i++) {
            sum = jinwei;
            for (int j = 0; j <= i; j++) {
                if (j < m && (i - j) < n) {
                    sum += (num1.charAt(m - 1 - j) - '0') * (num2.charAt(n - 1 - (i - j)) - '0');
                }
            }
            if (sum > 9) {
                arr[i] = (sum % 10);
                jinwei = sum / 10;
            } else {
                arr[i] = sum;
                jinwei = 0;
            }
        }
        if (jinwei > 0) arr[i++] = jinwei;
        StringBuilder res = new StringBuilder();
        for (int j = i - 1; j >= 0; j--) {
            res.append(arr[j]);
        }
        return res.toString();
    }

    /**
     * 方案四：先计算，统一进位：1ms
     */
    public static String multiply4(String num1, String num2) {
        if ("0".equals(num1) || "0".equals(num2)) {
            return "0";
        }
        int m = num1.length();
        int n = num2.length();
        int[] arr2 = new int[num2.length()];
        for (int i = 0; i < num2.length(); i++) {
            arr2[i] = num2.charAt(i) - '0';
        }
        int[] arr = new int[m + n];
        for (int i = m - 1; i >= 0; i--) {
            int x = num1.charAt(i) - '0';
            for (int j = n - 1; j >= 0; j--) {
                arr[m - i + n - j - 2] += x * arr2[j];
            }
        }
        // 统一进位
        int jinwei = 0;
        int i = 0;
        for (; i < m + n - 1; i++) {
            if (jinwei > 0) {
                arr[i] += jinwei;
            }
            if (arr[i] > 9) {
                jinwei = arr[i] / 10;
                arr[i] = arr[i] % 10;
            } else {
                jinwei = 0;
            }
        }
        if (jinwei > 0) {
            if (jinwei > 9) {
                arr[i++] = jinwei % 10;
                arr[i++] = jinwei / 10;
            } else {
                arr[i++] = jinwei;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (i = i - 1; i >= 0; i--) {
            sb.append(arr[i]);
        }
        return sb.toString();
    }
}
